/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace DaveSexton.DocProject.Sandcastle.TopicManagement
{
	internal sealed partial class CategoryTopicFilterControl : UserControl, ITopicFilterEditor
	{
		#region Public Properties
		[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public bool HasSelection
		{
			get
			{
				foreach (CheckBox check in categoriesTable.Controls)
					if (check.Checked)
						return true;

				foreach (CheckBox check in accessibilityTableLayoutPanel.Controls)
					if (check.Checked)
						return true;

				return false;
			}
		}

		[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public IEnumerable<TopicType> SelectedTypes
		{
			get
			{
				foreach (CheckBox control in categoriesTable.Controls)
				{
					if (control.Checked)
					{
						System.Diagnostics.Debug.WriteLine(control.Tag, "Search Topic Type Category");
						yield return (TopicType) control.Tag;
					}
				}
			}
			set
			{
				List<TopicType> types = (value == null) ? new List<TopicType>(0) : new List<TopicType>(value);

				foreach (CheckBox control in categoriesTable.Controls)
					control.Checked = types.Contains((TopicType) control.Tag);
			}
		}

		[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public IEnumerable<TopicAccessibility> SelectedAccessibility
		{
			get
			{
				bool includeProtected = false, includeInternal = false;

				foreach (CheckBox control in accessibilityTableLayoutPanel.Controls)
				{
					if (control.Checked)
					{
						TopicAccessibility access = (TopicAccessibility) control.Tag;

						System.Diagnostics.Debug.WriteLine(access, "Search Topic Accessibility Category");
						yield return access;

						if (access == TopicAccessibility.Protected)
							includeProtected = true;
						else if (access == TopicAccessibility.Internal)
							includeInternal = true;
					}
				}

				if (includeProtected && includeInternal)
					yield return TopicAccessibility.ProtectedInternal;
			}
			set
			{
				List<TopicAccessibility> access = (value == null) ? new List<TopicAccessibility>(0) : new List<TopicAccessibility>(value);

				foreach (CheckBox control in accessibilityTableLayoutPanel.Controls)
					control.Checked = access.Contains((TopicAccessibility) control.Tag);

				if (access.Contains(TopicAccessibility.ProtectedInternal))
				{
					protectedAccessCheckBox.Checked = true;
					internalAccessCheckBox.Checked = true;
				}
			}
		}

		[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public CategoryTopicFilter Filter
		{
			get
			{
				return boundFilter ?? new CategoryTopicFilter(SelectedTypes, SelectedAccessibility);
			}
		}
		#endregion

		#region Private / Protected
		private CategoryTopicFilter boundFilter;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="CategoryTopicFilterControl" /> class.
		/// </summary>
		public CategoryTopicFilterControl()
		{
			InitializeComponent();

			namespacesCheckBox.Tag = TopicType.Namespace;
			modulesCheckBox.Tag = TopicType.Module;
			classesCheckBox.Tag = TopicType.Class;
			structuresCheckBox.Tag = TopicType.Structure;
			interfacesCheckBox.Tag = TopicType.Interface;
			delegatesCheckBox.Tag = TopicType.Delegate;
			enumerationsCheckBox.Tag = TopicType.Enum;
			methodsCheckBox.Tag = TopicType.Method;
			propertiesCheckBox.Tag = TopicType.Property;
			fieldsCheckBox.Tag = TopicType.Field;
			eventsCheckBox.Tag = TopicType.Event;

			publicAccessCheckBox.Tag = TopicAccessibility.Public;
			privateAccessCheckBox.Tag = TopicAccessibility.Private;
			protectedAccessCheckBox.Tag = TopicAccessibility.Protected;
			internalAccessCheckBox.Tag = TopicAccessibility.Internal;
		}
		#endregion

		#region Methods
		public void LoadFilter(CategoryTopicFilter filter)
		{
			if (filter == null)
				throw new ArgumentNullException("filter");
			else if (boundFilter != null)
				throw new InvalidOperationException(Resources.Errors.CategoryTopicFilterAlreadyBound);

			SelectedTypes = filter.TopicTypes;
			SelectedAccessibility = filter.TopicAccess;
		}

		public void BindFilter(CategoryTopicFilter filter)
		{
			if (filter == null)
			{
				DataBindings.Clear();

				SelectedTypes = null;
				SelectedAccessibility = null;

				boundFilter = null;
			}
			else
			{
				SelectedTypes = filter.TopicTypes;
				SelectedAccessibility = filter.TopicAccess;

				boundFilter = filter;
			}
		}
		#endregion

		#region Event Handlers
		private void categories_CheckedChanged(object sender, EventArgs e)
		{
			if (boundFilter != null)
				boundFilter.TopicTypes = SelectedTypes;

			TopicFilterEditorTypeEventArgs args = new TopicFilterEditorTypeEventArgs(this.GetType());
			OnCanApplyChanged(args);
			OnCanSaveChanged(args);
		}

		private void accessType_CheckedChanged(object sender, EventArgs e)
		{
			if (boundFilter != null)
				boundFilter.TopicAccess = SelectedAccessibility;

			TopicFilterEditorTypeEventArgs args = new TopicFilterEditorTypeEventArgs(this.GetType());
			OnCanApplyChanged(args);
			OnCanSaveChanged(args);
		}
		#endregion

		#region ITopicFilterEditor Members
		[Browsable(false)]
		public bool CanApply
		{
			get
			{
				return HasSelection;
			}
		}

		[Browsable(false)]
		public bool CanSave
		{
			get
			{
				return HasSelection;
			}
		}

		string ITopicFilterEditor.Title
		{
			get
			{
				return Resources.Text.CategoryTopicFilter;
			}
		}

		ITopicFilter ITopicFilterEditor.Filter
		{
			get
			{
				return Filter;
			}
		}

		void ITopicFilterEditor.LoadFilter(ITopicFilter filter)
		{
			LoadFilter((CategoryTopicFilter) filter);
		}

		void ITopicFilterEditor.BindFilter(ITopicFilter filter)
		{
			BindFilter((CategoryTopicFilter) filter);
		}

		private readonly object CanApplyChangedEvent = new object();
		private readonly object CanSaveChangedEvent = new object();

		/// <summary>
		/// Event raised when the <see cref="CanSave"/> property value changes.
		/// </summary>
		[Category("Property Changed")]
		[Description("Event raised when the CanSave property value changes.")]
		public event EventHandler<TopicFilterEditorTypeEventArgs> CanSaveChanged
		{
			add
			{
				lock (CanSaveChangedEvent)
				{
					Events.AddHandler(CanSaveChangedEvent, value);
				}
			}
			remove
			{
				lock (CanSaveChangedEvent)
				{
					Events.RemoveHandler(CanSaveChangedEvent, value);
				}
			}
		}

		/// <summary>
		/// Raises the <see cref="CanSaveChanged" /> event.
		/// </summary>
		/// <param name="e"><see cref="TopicFilterEditorTypeEventArgs" /> object that provides the arguments for the event.</param>
		private void OnCanSaveChanged(TopicFilterEditorTypeEventArgs e)
		{
			EventHandler<TopicFilterEditorTypeEventArgs> handler = null;

			lock (CanSaveChangedEvent)
			{
				handler = (EventHandler<TopicFilterEditorTypeEventArgs>) Events[CanSaveChangedEvent];
			}

			if (handler != null)
				handler(this, e);
		}

		/// <summary>
		/// Event raised when the <see cref="CanApply"/> property value changes.
		/// </summary>
		[Category("Property Changed")]
		[Description("Event raised when the CanApply property value changes.")]
		public event EventHandler<TopicFilterEditorTypeEventArgs> CanApplyChanged
		{
			add
			{
				lock (CanApplyChangedEvent)
				{
					Events.AddHandler(CanApplyChangedEvent, value);
				}
			}
			remove
			{
				lock (CanApplyChangedEvent)
				{
					Events.RemoveHandler(CanApplyChangedEvent, value);
				}
			}
		}

		/// <summary>
		/// Raises the <see cref="CanApplyChanged" /> event.
		/// </summary>
		/// <param name="e"><see cref="TopicFilterEditorTypeEventArgs" /> object that provides the arguments for the event.</param>
		private void OnCanApplyChanged(TopicFilterEditorTypeEventArgs e)
		{
			EventHandler<TopicFilterEditorTypeEventArgs> handler = null;

			lock (CanApplyChangedEvent)
			{
				handler = (EventHandler<TopicFilterEditorTypeEventArgs>) Events[CanApplyChangedEvent];
			}

			if (handler != null)
				handler(this, e);
		}
		#endregion
	}
}
